CloudFoundry-Warden VS Docker
前言
Warden是现在被广泛使用在CloudFoundry中的容器技术,在CloudFoundry V3版本中,Warden被重新命名为Garden,我们暂且还是以V2版本做分析。众所周知,Docker是另一个易于使用并且很有效率的容器,所以现在CloudFoundry也支持Docker容器技术。接下来,我们就谈一谈Warden与Docker的相似和不同。
相似
都是依赖宿主操作系统内核的轻量级Container
目前,PaaS越来越多的与Container联系在一起,Container的高资源利用率恰恰是PaaS需要的。Warden和Docker都是Container的一种,相对于虚拟机来说,Container占用的资源比较少,都是依赖于宿主操作系统内核的轻量级容器。依赖于宿主机的操作系统,这样做会带来哪些好处呢?
一个虚拟机占用的资源比一个Container占用的资源多十几倍。设想一下,在一台物理机上启动100台虚拟机会是非常困难的,因为有硬件资源的限制,会出现CPU、硬盘或者内存资源用尽的情况。当相比之下,在一台物理机上启动100个Container是很简单的,因为作为Container,他会依赖于宿主机操作系统内核,仅仅在资源和服务等方面进行了隔离,启动快速,占用资源很少。现在很多大型的互联网公司都在大量地使用Container技术,Facebook一台虚机都没有,因为这些互联网公司要求充分利用计算资源。虚机起码还要再跑一个Guest系统,太耗资源。同时,在这些大公司内部并没有很多操作系统,集群只有一种操作系统,甚至连版本号都是固定的。因此,不需要虚机的异构操作系统特性。另外,在操作系统上还有Runtime Library,Container不需要重复加载,极大的节省内存占用。
都是基于C/S架构的设计方案
Docker是C/S的架构,分为Docker client 和 Docker daemon,client端发送命令,daemon端负责完成client发送过来的命令(如获取和存储镜像、管理容器等)。两者之间可以通过 TCP,HTTP和UNIX SOCKET来进行通信;
Warden也是基于C/S架构的一个设计方案。大体可以分为三个模块:Warden server、Warden client和Warden protocol,三者之间可以相互通信服务。server和client都对protocol达成理解,如果其中一端发生一些变化,另一端不需要做太多的修改即可适配。
都采用了linux内核技术实现容器隔离(namespace)和资源限制(cgroup)
对于无论是Warden还是Docker来说,提供一个隔离的运行环境都是必要的。之所以称两者为容器,就是这个原因。Linux的内核特性namespace和cgroup提供容器隔离的功能。namespace主要负责命名空间的隔离,而cgroup主要负责资源使用的限制。
Linux内核实现namespace的主要目的就是为了服务于轻量级容器,实现了隔离之后,在同一个namespace之下的进程可以感知到彼此的变化。当我们启动一个容器时会经历下面几个步骤:父进程通过fork创建子进程时,使用namespace技术,实现子进程与其他进程的命名空间的隔离;子进程创建完毕之后,使用cgroup技术来处理子进程,实现进程的资源使用限制;系统在子进程所处的namespace内部,创建需要的隔离环境,如隔离的网络栈等;namespace和cgroup两种技术都使用上之后,进程所处的隔离环境在真正建立,容器才会创建完成。
cgroups可以实现Docker组进程并且管理它们的资源总消耗、分享可用的硬件资源给不同的容器、限制容器的内存和CPU使用(可以通过更改相应的cgroup来调整容器的大小,通过检查Linux中的/sys/fs/cgroup对照组来获取容器中的资源使用情况)、提供了一组可靠的技术容器所有进程的方法。
Warden使用cgroup实现对进程内存的资源隔离和限制。在Warden/Warden/lib/Warden/container/features/mem_limit.rb中的do_limit_memory函数中实现。dea可以通过接口控制Warden设置对容器内存占用的限制。do_limit_memory主要做以下两部分工作:启动oom进程,用于处理oom通知。向容器对应的cgroup目录中的memory.limit_in_bytes、memory.memsw.limit_in_bytes文件中写入内存上限值。Warden使用cgroup实现对进程cpu的资源隔离和限制。Warden在这方面都使用默认值,不向外提供控制接口。除了使用cgroup之外,Warden使用quotal和traffic control来控制memory、disk以及网络I/O。
都使用了aufs文件系统
aufs是一种支持联合挂载的文件系统,支持将不同的目录挂载到同一个目录下,并实现一种layer的概念。aufs将挂载到统一虚拟文件系统下的多个目录分别设置成read-only,read-write,对于read-only目录只能是只读的,写操作只能在read-write目录中。我们在使用aufs时,一般都会使用mount命令。在挂载的过程中,mount命令按照命令行中给出的文件夹顺序挂载,若出现有同名文件的情况,则以先挂载的为主,其他的不再挂载。这也说明了的Docker镜像为什么采用增量的方式:完全是利用Aufs的特性达到节约空间的目的。
对于Warden来说,每一个容器都有一个私有的根文件系统,这个系统由一个只读文件系统和一个可读写文件系统堆叠而成,只读文件系统包含了ubuntu软件包的最小子集和Warden针对所有容器的定制部分。
不同
用途不同
Warden是CF内部的一个轻量级的容器,只包含容器部分。在我们实际使用时,Warden大多数情况下还是存在于DEA组件中,而DEA是CloudFoundry的一个组件,也就是说,一般情况下Warden容器在CloudFoundry集群中应用很多,虽然现在Warden容器也可以单独部署,但并没有docker使用便捷。
相比之下,Docker更全面,Docker除了容器部分还包含镜像管理,镜像仓库,服务发现,selinux等,提供了一个独立运行Linux进程的轻量级虚拟化解决方案。 Docker的轻量级容器不仅实现了资源隔离,而且几乎可以运行在任何地方,使得部署和扩展变得非常容易,随着Docker的日趋完善,希望Docker被越来越多的公司应用到生产环境中。
交互方式
Docker提供了http的REST接口
Warden提供了交互的协议,通过unix socket域和外部进程(DEA)通信
Docker的文件系统更复杂
由于Warden是CloudFoundry平台一部分,所以它不需要许多文件系统的支持,它只依附于AUFS和OverlayFS。然而Docker的文件系统更为复杂,他覆盖更多的联合文件系统,比如 Btrfs, ZFS, VFS,等等。
镜像管理方式不同
Warden与Docker最大的不同就体现在镜像的管理方式上。Warden在运行应用之前可以从buildpacks获得所需要的依赖。Warden通常情况下只需要两层layer,一个是只读文件系统,一个可读写文件系统,如下图
与Warden不同的是,Docker设计之初就是为了运行镜像,可以说镜像是Docker中最重要的一部分。对于一个应用来说,在它可以运行在Docker之前,你需要为他创建一个镜像。Docker镜像包含了许多层,这些层结合在一起形成了Docker的文件系统。当我们想基于其他的镜像来创建我们自己的镜像时,Docker就会复用这些layer。Docker镜像在启动时,在bootfs自检完成之后并不会把rootfs的read-only改为read-write,而是利用union mount将一个或者多个read-only的rootfs加载到之前的rootfs层之上。在加载了N多个层之后,他们组合成一个文件系统,这个文件系统就是Docker的镜像,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。Docker的架构中,Docker镜像就是类似于“ubuntu操作系统发行版”,可以在任何满足要求的Linux内核之上运行。简单一点有“Debian操作系统发行版”Docker镜像、“Ubuntu操作系统发行版”Docker镜像;如果在Debian镜像中安装MySQL 5.6,那我们可以将其命名为Mysql:5.6镜像;如果在Debian镜像中安装有Golang 1.3,那我们可以将其命名为golang:1.3镜像;以此类推,大家可以根据自己安装的软件,得到任何自己想要的镜像。包含:镜像层文件和镜像json文件。如一个ubuntu:14.04镜像,包含4个镜像层,在aufs存储驱动的情况下,可以参考下面这张图: